/*
 * @Author: Troubadour 2276791354@qq.com
 * @Date: 2024-08-14 22:45:49
 * @LastEditors: Troubadour 2276791354@qq.com
 * @LastEditTime: 2024-08-18 20:30:01
 * @Version:
 * @Description:
 */

/*-------------------------------------------------------------------------------------------------------------------------------------
-                                                  Include file                                                                       -
--------------------------------------------------------------------------------------------------------------------------------------*/
#include "tft_drv.h"
#include "bsp_type.h"
#include "cola_device.h"

#include "FreeRTOS.h"
#include "task.h"
/*-------------------------------------------------------------------------------------------------------------------------------------
-                                                  Internal macro                                                                     -
--------------------------------------------------------------------------------------------------------------------------------------*/

#define TFT_DELAY_MS(ms)                        vTaskDelay(pdMS_TO_TICKS(ms))


#define TFT_SPI_DEV_NAME "bsp_spi"
#define TFT_SPI_WRITE(dev, pos, buffer, size)   cola_device_write(dev, pos, buffer, size)
#define TFT_SPI_READ(dev, pos, buffer, size)    cola_device_read(dev, pos, buffer, size)
#define TFT_SPI_CFG(dev, type, args)            cola_device_ctrl(dev, type, args)

#define TFT_GPIO_DEV_NAME "bsp_gpio"
#define TFT_GPIO_WRITE(dev, pin, state)         cola_device_ctrl(dev, pin, state)

#define ST7735_NOP			0x00	//空命令
#define ST7735_SWRESET		0x01	//软件复位，在睡眠和显示模式下，重置软件后需等待120ms后方可执行下一条指令
#define ST7735_RDDID		0x04	//读取LCD的制造商ID（8位）、驱动版本ID（最高位为1，7位）、驱动程序ID（8位）
#define ST7735_RDDST		0x09	//读取显示屏所有状态参数
#define ST7735_RDDPM		0x0A	//读取显示屏能量模式
#define ST7735_RDDMADCTL	0x0B	//读取显示屏MADCTL
#define ST7735_RDDCOLMOD	0x0C	//读取显示屏像素定义
#define ST7735_RDDIM		0x0D	//读取显示屏图片模式
#define ST7735_RDDSM		0x0E	//读取显示屏单信号模式
#define ST7735_RDDSDR		0x0F	//读取显示屏自我诊断结果
#define ST7735_SLPIN		0x10	//进入最小功耗模式
#define ST7735_SLPOUT 		0x11	//关闭睡眠模式
#define ST7735_PTLON		0x12	//打开Partial模式
#define ST7735_NORON		0x13	//恢复到正常模式
#define ST7735_INVOFF		0x20	//显示反转模式中恢复
#define ST7735_INVON		0x21	//进入反向显示模式
#define ST7735_GAMSET		0x26	//当前显示选择所需的伽马曲线
#define ST7735_DISPOFF		0x28	//关闭显示，帧内存的输出被禁用
#define ST7735_DISPON		0x29	//开启显示，帧内存的输出被启用
#define ST7735_CASET		0x2A	//列地址设置，每个值代表帧内存中的一列
#define ST7735_RASET		0x2B	//行地址设置，每个值代表帧内存中的一列
#define ST7735_RAMWR		0x2C	//写入内存
#define ST7735_RGBSET		0x2D	//颜色模式设置
#define ST7735_RAMRD		0x2E	//读取内存
#define ST7735_PTLAR		0x30	//部分模式的显示区域设置
#define ST7735_SCRLAR		0x33	//定义垂直滚动区域的显示
#define ST7735_TEOFF		0x34	//关闭(Active Low) TE信号线的撕裂效应输出信号
#define ST7735_TEON		    0x35	//打开TE信号线的撕裂效果输出信号
#define ST7735_MADCTL		0x36	//定义帧内存的读写扫描方向
#define ST7735_MADCTL_MX    0x40
#define ST7735_MADCTL_MY    0x80
#define ST7735_MADCTL_MV    0x20
#define ST7735_VSCSAD		0x37	//设置垂直滚动起始地址，此命令与垂直滚动定义(33h)一起使用
#define ST7735_IDMOFF		0x38	//关闭空闲模式
#define ST7735_IDMON		0x39	//开启空闲模式
#define ST7735_COLMOD		0x3A	//定义通过MCU接口传输的RGB图片数据的格式
#define ST7735_FRMCTR1		0xB1	//设置全色正常模式的帧频
#define ST7735_FRMCTR2 	    0xB2	//设置空闲模式的帧频
#define ST7735_FRMCTR3 	    0xB3	//设置部分模式/全色的帧频率
#define ST7735_INVCTR 		0xB4	//反转模式控制
#define ST7735_PWCTR1 		0xC0	//设置AVDD、MODE、VRHP、VRHN
#define ST7735_PWCTR2 		0xC1	//设置VGH与VGL的供电功率
#define ST7735_PWCTR3 		0xC2	//设置正常模式/全色模式下的运放的电流
#define ST7735_PWCTR4 		0xC3	//设置空闲模式/八色模式下的运放的电流
#define ST7735_PWCTR5 		0xC4	//设置部分模式/全色模式下的运放的电流
#define ST7735_VMCTR1 		0xC5	//设置VCOM电压电平以减少闪烁问题
#define ST7735_VMOFCTR		0xC7	//VCOM偏移控制，在使用命令0xC7之前，命令0xD9的位VMF_EN必须启用(设置为1)
#define ST7735_WRID2		0xD1	//写入LCD模块版本的7位数据，保存到NVM
#define ST7735_WRID3		0xD2	//写入项目代码模块的8位数据，保存到NVM
#define ST7735_NVFCTR1		0xD9	//NVM状态控制
#define ST7735_RDID1		0xDA	//读字节返回8位LCD模块的制造商ID
#define ST7735_RDID2		0xDB	//读字节返回8位LCD模块/驱动程序版本ID
#define ST7735_RDID3		0xDC	//读字节返回8位LCD模块/驱动ID
#define ST7735_NVFCTR2		0xDE	//NVM读取命令
#define ST7735_NVFCTR3		0xDF	//NVM写取命令
#define ST7735_GMCTRP1		0xE0	//Gamma ‘+’ Polarity Correction Characteristics Setting
#define ST7735_GMCTRN1		0xE1	//Gamma ‘+’ Polarity Correction Characteristics Setting
#define ST7735_GCV			0xFC	//自动调节门泵时钟，节省功耗

/*-------------------------------------------------------------------------------------------------------------------------------------
-                                                  Internal enum                                                                      -
--------------------------------------------------------------------------------------------------------------------------------------*/

/*-------------------------------------------------------------------------------------------------------------------------------------
-                                                  Internal structure                                                                 -
--------------------------------------------------------------------------------------------------------------------------------------*/

typedef struct
{
    uint8_t cs_state;    /* Control CS pin.  0: Select device    1: Release device. */
    uint8_t dc_state;    /* Control DC pin.  0: write command,   1: write data. */
    uint8_t reset_state; /* Control RST pin. 0: No reset,        1: Reset */
    int spi_speed;       /* Configure SPI speed. Unit: 1Hz */
    uint8_t spi_mode;    /* Configure SPI mode. 0: Mode 0, 1: Mode 1, 2: Mode 2, 3: Mode 3 */
    cola_device_t *spi_drv;
    cola_device_t *gpio_drv;
} TFT_CXT;
/*-------------------------------------------------------------------------------------------------------------------------------------
-                                                  Internal function                                                                  -
--------------------------------------------------------------------------------------------------------------------------------------*/

/*-------------------------------------------------------------------------------------------------------------------------------------
-                                                  Internal variables                                                                 -
--------------------------------------------------------------------------------------------------------------------------------------*/

static TFT_CXT tft_cxt = {
    .spi_speed = 1000000,
    .spi_mode = 1,
};
static uint8_t SendBuff[4] = {0};
static uint8_t DrawRectangle[ST7735_WIDTH * 2] = {0};
static uint8_t DrawRectangleLVGL[ST7735_WIDTH * 2] = {0};
static uint8_t DrawPoint[2] = {0};
/*-------------------------------------------------------------------------------------------------------------------------------------
-                                                  External variables                                                                 -
--------------------------------------------------------------------------------------------------------------------------------------*/

/*-------------------------------------------------------------------------------------------------------------------------------------
-                                                  Function body                                                                      -
--------------------------------------------------------------------------------------------------------------------------------------*/

static void TFT_Reset(TFT_CXT *tft_dev)
{
    tft_cxt.reset_state = 0;
    TFT_GPIO_WRITE(tft_dev->gpio_drv, (int)EN_GPIO_CTRL_RST, &tft_cxt.reset_state);
    TFT_DELAY_MS(100);
    tft_cxt.reset_state = 1;
    TFT_GPIO_WRITE(tft_dev->gpio_drv, (int)EN_GPIO_CTRL_RST, &tft_cxt.reset_state);
    TFT_DELAY_MS(50);
}

static void TFT_Write_Cmd(TFT_CXT *tft_dev, uint8_t cmd)
{
    tft_cxt.dc_state = 0;
    TFT_GPIO_WRITE(tft_dev->gpio_drv, (int)EN_GPIO_CTRL_DC, &tft_cxt.dc_state);
    tft_cxt.cs_state = 0;
    TFT_GPIO_WRITE(tft_dev->gpio_drv, (int)EN_GPIO_CTRL_CS, &tft_cxt.cs_state);

    TFT_SPI_WRITE(tft_dev->spi_drv, 0, &cmd, 1);

    tft_cxt.cs_state = 1;
    TFT_GPIO_WRITE(tft_dev->gpio_drv, (int)EN_GPIO_CTRL_CS, &tft_cxt.cs_state);
}

static void TFT_Write_Data(TFT_CXT *tft_dev, uint8_t data)
{
    tft_cxt.dc_state = 1;
    TFT_GPIO_WRITE(tft_dev->gpio_drv, (int)EN_GPIO_CTRL_DC, &tft_cxt.dc_state);
    tft_cxt.cs_state = 0;
    TFT_GPIO_WRITE(tft_dev->gpio_drv, (int)EN_GPIO_CTRL_CS, &tft_cxt.cs_state);

    TFT_SPI_WRITE(tft_dev->spi_drv, 0, &data, 1);

    tft_cxt.cs_state = 1;
    TFT_GPIO_WRITE(tft_dev->gpio_drv, (int)EN_GPIO_CTRL_CS, &tft_cxt.cs_state);
}

static void TFT_Write_DataBuff(TFT_CXT *tft_dev, uint8_t *data, uint16_t len)
{
    tft_cxt.dc_state = 1;
    TFT_GPIO_WRITE(tft_dev->gpio_drv, (int)EN_GPIO_CTRL_DC, &tft_cxt.dc_state);
    tft_cxt.cs_state = 0;
    TFT_GPIO_WRITE(tft_dev->gpio_drv, (int)EN_GPIO_CTRL_CS, &tft_cxt.cs_state);

    TFT_SPI_WRITE(tft_dev->spi_drv, 0, data, len);

    tft_cxt.cs_state = 1;
    TFT_GPIO_WRITE(tft_dev->gpio_drv, (int)EN_GPIO_CTRL_CS, &tft_cxt.cs_state);
}

int TFT_Init(void)
{
    EN_SPI_CFG_TYPE cfg_type;

    tft_cxt.spi_drv = cola_device_find(TFT_SPI_DEV_NAME);
    if (tft_cxt.spi_drv == NULL)
    {
        return TFT_DRV_STATE_ERR;
    }
    tft_cxt.gpio_drv = cola_device_find(TFT_GPIO_DEV_NAME);
    if (tft_cxt.gpio_drv == NULL)
    {
        return TFT_DRV_STATE_ERR;
    }

    /* Configuration SPI speed. */
    cfg_type = EN_SPI_CFG_SPEED;
    cola_device_cfg(tft_cxt.spi_drv, &cfg_type, &tft_cxt.spi_speed);
    /* configuration SPI mode. */
    cfg_type = EN_SPI_CFG_MODE;
    cola_device_cfg(tft_cxt.spi_drv, &cfg_type, &tft_cxt.spi_mode);
    /* Open SPI. */
    cola_device_open(tft_cxt.spi_drv, 0);

    /* Reset display */
    TFT_Reset(&tft_cxt);
    TFT_BackLight(1);

    /* Configure ST7735 Frame Rate */
    TFT_Write_Cmd(&tft_cxt, ST7735_SLPOUT);
    TFT_DELAY_MS(100);

    TFT_Write_Cmd(&tft_cxt, ST7735_FRMCTR1);
    TFT_Write_Data(&tft_cxt, 0x01);
    TFT_Write_Data(&tft_cxt, 0x2C);
    TFT_Write_Data(&tft_cxt, 0x2D);

    TFT_Write_Cmd(&tft_cxt, ST7735_FRMCTR2);
    TFT_Write_Data(&tft_cxt, 0x01);
    TFT_Write_Data(&tft_cxt, 0x2C);
    TFT_Write_Data(&tft_cxt, 0x2D);

    TFT_Write_Cmd(&tft_cxt, ST7735_FRMCTR3);
    TFT_Write_Data(&tft_cxt, 0x01);
    TFT_Write_Data(&tft_cxt, 0x2C);
    TFT_Write_Data(&tft_cxt, 0x2D);
    TFT_Write_Data(&tft_cxt, 0x01);
    TFT_Write_Data(&tft_cxt, 0x2C);
    TFT_Write_Data(&tft_cxt, 0x2D);

    TFT_Write_Cmd(&tft_cxt, ST7735_INVCTR);
    TFT_Write_Data(&tft_cxt, 0x07);

    /* Configure ST7735 Power Sequence */
    TFT_Write_Cmd(&tft_cxt, ST7735_PWCTR1);
    TFT_Write_Data(&tft_cxt, 0xA2);
    TFT_Write_Data(&tft_cxt, 0x02);
    TFT_Write_Data(&tft_cxt, 0x84);
    TFT_Write_Cmd(&tft_cxt, ST7735_PWCTR2);
    TFT_Write_Data(&tft_cxt, 0xC5);
    TFT_Write_Cmd(&tft_cxt, ST7735_PWCTR3);
    TFT_Write_Data(&tft_cxt, 0x0A);
    TFT_Write_Data(&tft_cxt, 0x00);
    TFT_Write_Cmd(&tft_cxt, ST7735_PWCTR4);
    TFT_Write_Data(&tft_cxt, 0x8A);
    TFT_Write_Data(&tft_cxt, 0x2A);
    TFT_Write_Cmd(&tft_cxt, ST7735_PWCTR5);
    TFT_Write_Data(&tft_cxt, 0x8A);
    TFT_Write_Data(&tft_cxt, 0xEE);

    TFT_Write_Cmd(&tft_cxt, ST7735_VMCTR1); // VCOM
    TFT_Write_Data(&tft_cxt, 0x0E);

    TFT_Write_Cmd(&tft_cxt, ST7735_INVERSE ? ST7735_INVON : ST7735_INVOFF);
    TFT_Write_Cmd(&tft_cxt, ST7735_COLMOD);
    TFT_Write_Data(&tft_cxt, 0x05);

    TFT_Write_Cmd(&tft_cxt, ST7735_CASET);
    TFT_Write_Data(&tft_cxt, 0x00);
    TFT_Write_Data(&tft_cxt, 0x00);
    TFT_Write_Data(&tft_cxt, 0x00);
    TFT_Write_Data(&tft_cxt, 0x7F);

    TFT_Write_Cmd(&tft_cxt, ST7735_RASET);
    TFT_Write_Data(&tft_cxt, 0x00);
    TFT_Write_Data(&tft_cxt, 0x00);
    TFT_Write_Data(&tft_cxt, 0x00);
    TFT_Write_Data(&tft_cxt, 0x9F);

    TFT_Write_Cmd(&tft_cxt, ST7735_GMCTRP1);
    TFT_Write_Data(&tft_cxt, 0x02);
    TFT_Write_Data(&tft_cxt, 0x1C);
    TFT_Write_Data(&tft_cxt, 0x07);
    TFT_Write_Data(&tft_cxt, 0x12);
    TFT_Write_Data(&tft_cxt, 0x37);
    TFT_Write_Data(&tft_cxt, 0x32);
    TFT_Write_Data(&tft_cxt, 0x29);
    TFT_Write_Data(&tft_cxt, 0x2D);
    TFT_Write_Data(&tft_cxt, 0x29);
    TFT_Write_Data(&tft_cxt, 0x25);
    TFT_Write_Data(&tft_cxt, 0x2B);
    TFT_Write_Data(&tft_cxt, 0x39);
    TFT_Write_Data(&tft_cxt, 0x00);
    TFT_Write_Data(&tft_cxt, 0x01);
    TFT_Write_Data(&tft_cxt, 0x03);
    TFT_Write_Data(&tft_cxt, 0x10);
    TFT_Write_Cmd(&tft_cxt, ST7735_GMCTRN1);
    TFT_Write_Data(&tft_cxt, 0x03);
    TFT_Write_Data(&tft_cxt, 0x1D);
    TFT_Write_Data(&tft_cxt, 0x07);
    TFT_Write_Data(&tft_cxt, 0x06);
    TFT_Write_Data(&tft_cxt, 0x2E);
    TFT_Write_Data(&tft_cxt, 0x2C);
    TFT_Write_Data(&tft_cxt, 0x29);
    TFT_Write_Data(&tft_cxt, 0x2D);
    TFT_Write_Data(&tft_cxt, 0x2E);
    TFT_Write_Data(&tft_cxt, 0x2E);
    TFT_Write_Data(&tft_cxt, 0x37);
    TFT_Write_Data(&tft_cxt, 0x3F);
    TFT_Write_Data(&tft_cxt, 0x00);
    TFT_Write_Data(&tft_cxt, 0x00);
    TFT_Write_Data(&tft_cxt, 0x02);
    TFT_Write_Data(&tft_cxt, 0x10);

    TFT_Write_Cmd(&tft_cxt, ST7735_NORON);
    TFT_DELAY_MS(10);
    TFT_Write_Cmd(&tft_cxt, ST7735_DISPON);
    TFT_DELAY_MS(10);

    TFT_SetRotation(ST7735_ROTATION);
    return TFT_DRV_STATE_OK;
}

void TFT_BackLight(uint8_t state)
{
    TFT_GPIO_WRITE(tft_cxt.gpio_drv, (int)EN_GPIO_CTRL_BK, &state);
}

void TFT_SetRotation(uint8_t rotation)
{
    uint8_t madctl = 0;

    switch (rotation)
    {
    case 0:
        madctl = ST7735_MADCTL_MX | ST7735_MADCTL_MY | ST7735_MADCTL_MODE;
        break;
    case 1:
        madctl = ST7735_MADCTL_MY | ST7735_MADCTL_MV | ST7735_MADCTL_MODE;
        break;
    case 2:
        madctl = ST7735_MADCTL_MODE;
        break;
    case 3:
        madctl = ST7735_MADCTL_MX | ST7735_MADCTL_MV | ST7735_MADCTL_MODE;
        break;
    }

    TFT_Write_Cmd(&tft_cxt, ST7735_MADCTL);
    TFT_Write_Data(&tft_cxt, madctl);
}

void ST7735_SetAddressWindow(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1)
{
    x0 += ST7735_XSTART;
    y0 += ST7735_YSTART;
    x1 += ST7735_XSTART;
    y1 += ST7735_YSTART;

    SendBuff[0] = 0x00;
    SendBuff[1] = x0;
    SendBuff[2] = 0x00;
    SendBuff[3] = x1;
    TFT_Write_Cmd(&tft_cxt, ST7735_CASET);
    TFT_Write_DataBuff(&tft_cxt, SendBuff, 4);

    TFT_Write_Cmd(&tft_cxt, ST7735_RASET);
    SendBuff[1] = y0;
    SendBuff[3] = y1 + 1;
    TFT_Write_DataBuff(&tft_cxt, SendBuff, 4);

    TFT_Write_Cmd(&tft_cxt, ST7735_RAMWR);
}


void TFT_DrawPoint(uint8_t x, uint8_t y, uint16_t color)
{
    DrawPoint[0] = (uint8_t)(color >> 8);
    DrawPoint[1] = (uint8_t)(color);
    ST7735_SetAddressWindow(x, y, x + 1, y + 1);
    TFT_Write_DataBuff(&tft_cxt, DrawPoint, 2);
}

void ST7735_DrawRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color)
{
    DrawRectangle[0] = (uint8_t)(color >> 8);
    DrawRectangle[1] = (uint8_t)(color);

    ST7735_SetAddressWindow(x, y, x + width - 1, y + height - 1);

    for (uint8_t i = 0; i < width; i++)
    {
        for (uint8_t j = 0; j < height; j++)
        {
            TFT_Write_DataBuff(&tft_cxt, DrawRectangle, 2);
        }
    }
}

void ST7735_DrawRectangleLVGL(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint16_t *color)
{
    uint16_t i = 0, j = 0;
    uint16_t height = y1 - y0 + 1;
    uint16_t width = x1 - x0 + 1;

    ST7735_SetAddressWindow(x0, y0, x1, y1);

    for (i = 0; i < height; i++)
    {
        for (j = 0; j < width; j++)
        {
            DrawRectangleLVGL[j * 2] = *color >> 8;
            DrawRectangleLVGL[j * 2 + 1] = *color & 0xFF;
            *color++;
        }
        TFT_Write_DataBuff(&tft_cxt, DrawRectangleLVGL, sizeof(uint16_t) * width);
    }
}

void TFT_Clear(uint16_t color)
{
    ST7735_DrawRectangle(0, 0, ST7735_WIDTH, ST7735_HEIGHT, color);
}
